/*******************************************************************************
 * The MOSES project, model based software engineering of networked embedded systems.
 * 
 * Copyright (C) 2010-2013, University of Applied Sciences Wildau,
 * Telematics Research Group, http://www.tm.th-wildau.de/research-group
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses>.
 * 
 * Contributors:
 *     University of Applied Sciences Wildau - initial API and implementation
 * 
 * If you are interested in a commercial license please contact us via 
 * e-mail: ralf.vandenhouten@th-wildau.de.
 ******************************************************************************/
package de.thwildau.tm.moses.examples.nmea.app;

import java.awt.DisplayMode;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.local.DefaultLocalClientChannelFactory;
import org.jboss.netty.channel.local.DefaultLocalServerChannelFactory;
import org.jboss.netty.channel.local.LocalAddress;
import org.jboss.netty.handler.stream.ChunkedFile;
import org.jboss.netty.handler.stream.ChunkedWriteHandler;

import de.thwildau.tm.moses.examples.nmea.data.Nmea;

/**
 * @author Thomas Kistel
 */
public class MainFrame extends javax.swing.JFrame implements NmeaMessageListener {

    private static final long serialVersionUID = 1L;


    /**
     * Creates new form MainFrame
     */
    public MainFrame() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this
     * code. The content of this method is always regenerated by the Form Editor.
     */
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        gpsData = new javax.swing.JTable();
        exitButton = new javax.swing.JButton();
        chooseButton = new javax.swing.JButton();
        serialPortButton = new javax.swing.JButton();
        saveButton = new javax.swing.JButton();
        dserialPortButton = new javax.swing.JButton();
        fc = new javax.swing.JFileChooser();
        fftxt = new javax.swing.filechooser.FileNameExtensionFilter("formless Text-File(.txt)", "txt");
        ffcsv = new javax.swing.filechooser.FileNameExtensionFilter("Comma-separated values(.csv)", "csv");
        fflog = new javax.swing.filechooser.FileNameExtensionFilter("Log-File(.log)", "log");
        model = new NmeaTableModel();
        spc = new SerialPortConnecter(this);

        this.setResizable(false);

        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fc.setAcceptAllFileFilterUsed(false);
        fc.addChoosableFileFilter(fftxt);
        fc.addChoosableFileFilter(ffcsv);
        fc.addChoosableFileFilter(fflog);

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        gpsData.setModel(model);
        jScrollPane1.setViewportView(gpsData);

        exitButton.setText("Exit");
        exitButton.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitButtonActionPerformed(evt);
            }
        });

        chooseButton.setText("Choose File");
        chooseButton.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                chooseButtonActionPerformed(evt);
            }
        });

        serialPortButton.setText("Connect serial port");
        serialPortButton.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                serialPortButtonActionPerformed(evt);
            }
        });

        dserialPortButton.setText("Disconnect serial port");
        dserialPortButton.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                dserialPortButtonActionPerformed(evt);
            }
        });

        saveButton.setText("Save to file");
        saveButton.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                layout.createSequentialGroup().addContainerGap().addComponent(chooseButton).addPreferredGap(
                        javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(serialPortButton).addPreferredGap(
                        javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(dserialPortButton).addPreferredGap(
                        javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(saveButton).addPreferredGap(
                        javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE,
                        Short.MAX_VALUE).addComponent(exitButton).addContainerGap()).addComponent(jScrollPane1,
                javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 581, Short.MAX_VALUE));
        layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                layout.createSequentialGroup().addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 371,
                        Short.MAX_VALUE).addGap(18, 18, 18).addGroup(
                        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(exitButton).addComponent(
                                chooseButton).addComponent(serialPortButton).addComponent(dserialPortButton).addComponent(
                                saveButton)).addContainerGap()));

        pack();
    }

    /*
     * (non-Javadoc)
     * @see NmeaMessageListener#newNmeaData(de.thwildau.tm.moses.examples.nmea.data.NMEA)
     */
    @Override
    public void newNmeaData(Nmea nmea) {
        model.addGPS(nmea);
    }

    private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {
        this.setVisible(false);
        System.exit(EXIT_ON_CLOSE);
    }

    private void chooseButtonActionPerformed(java.awt.event.ActionEvent evt) {
        fc.setDialogTitle("Choose File");
        fc.showOpenDialog(this);
        File file;
        if ((file = fc.getSelectedFile()) != null) {
            readFile(file);
        }
    }

    private void readFile(File file) {
        if (!file.exists())
            throw new IllegalArgumentException("The file " + file.getAbsolutePath() + " does not exist.");
        if (file.isDirectory())
            throw new IllegalArgumentException("The file " + file.getAbsolutePath() + " is a directory.");

        try {
            // create a local address that local-client and local-server share
            LocalAddress address = new LocalAddress(1);

            // create a local-server that receives the file content. The local-server
            // uses the NmeaPipelineFactory to decode the file content
            ServerBootstrap sb = new ServerBootstrap(new DefaultLocalServerChannelFactory());
            sb.setPipelineFactory(new NmeaPipelineFactory(this));
            sb.bind(address);

            // create a local-client that open's the file and writes the content into
            // a channel so that the content can be decoded on the local-server side
            ClientBootstrap cb = new ClientBootstrap(new DefaultLocalClientChannelFactory());
            cb.getPipeline().addLast("writer", new ChunkedWriteHandler());
            ChannelFuture cf = cb.connect(address);
            ChannelFuture writeFuture = cf.getChannel().write(new ChunkedFile(file));
            writeFuture.awaitUninterruptibly();
            cf.getChannel().close();
            // Wait until the connection is closed or the connection attempt fails.
            cf.getChannel().getCloseFuture().awaitUninterruptibly();

            // Release all resources used by the local transport.
            cb.releaseExternalResources();
            sb.releaseExternalResources();
            

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void serialPortButtonActionPerformed(java.awt.event.ActionEvent evt) {
        if (spc.isExit()) {
            new SerialPortFrame(spc, this).setVisible(true);
        } else {
            JOptionPane.showMessageDialog(this, "Please first disconnect old session!", "open Connection",
                    JOptionPane.ERROR_MESSAGE);
        }
    }

    private void dserialPortButtonActionPerformed(java.awt.event.ActionEvent evt) {
        if (!spc.isExit()) {
            spc.disconnect();
            JOptionPane.showMessageDialog(this, "Serial Port Disconnected!");
        } else {
            JOptionPane.showMessageDialog(this, "No serial port connection exist!", "no Connection",
                    JOptionPane.ERROR_MESSAGE);
        }
    }

    private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {
        fc.setDialogTitle("Save File");
        if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
            String path = fc.getSelectedFile().toString().substring(fc.getSelectedFile().toString().length() - 4,
                    fc.getSelectedFile().toString().length());

            if (!(path.equals(".txt") || path.equals(".csv") || path.equals(".log"))) {
                if (fc.getFileFilter().equals(fftxt)) {
                    writeToFile(fc.getSelectedFile(), ".txt");
                }
                if (fc.getFileFilter().equals(ffcsv)) {
                    writeToFile(fc.getSelectedFile(), ".csv");
                }
                if (fc.getFileFilter().equals(fflog)) {
                    writeToFile(fc.getSelectedFile(), ".log");
                }
            } else {
                writeToFile(fc.getSelectedFile(), "");
            }
        }
    }

    private void writeToFile(File file, String ext) {
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
            DataOutput dataOut = new DataOutputStream(new FileOutputStream(file.getPath() + ext));
            for (Nmea nmea : model.getNMEAS()) {
                nmea.write(dataOut);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                javax.swing.JFrame j = new MainFrame();
                GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
                GraphicsDevice gd = env.getDefaultScreenDevice();
                DisplayMode dm = gd.getDisplayMode();
                int posY = dm.getHeight() / 2 - j.getSize().height / 2;
                int posX = dm.getWidth() / 2 - j.getSize().width / 2;
                j.setLocation(posX, posY);
                j.setVisible(true);
            }
        });
    }


    private javax.swing.JButton chooseButton;
    private javax.swing.JButton exitButton;
    private javax.swing.JButton serialPortButton;
    private javax.swing.JButton dserialPortButton;
    private javax.swing.JButton saveButton;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable gpsData;
    private SerialPortConnecter spc;
    private javax.swing.JFileChooser fc;
    private javax.swing.filechooser.FileFilter fflog;
    private javax.swing.filechooser.FileFilter ffcsv;
    private javax.swing.filechooser.FileFilter fftxt;
    private NmeaTableModel model;
}
